package com.liuyang.demo.mybatis.enums.handler;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.lang.reflect.ParameterizedType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: libin
 * @date: 2020/3/18 11:28
 * @what:
 */
public class ListEnumTypeHandler<E extends BaseEnumInterface> extends BaseTypeHandler<List<E>> {

    private final Class<E> type;

    public ListEnumTypeHandler() {
        type = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<E> parameter, JdbcType jdbcType) throws SQLException {
        if (parameter != null) {
            List<Integer> p = parameter.stream().map(e -> e.getValue()).collect(Collectors.toList());
            p.sort(Integer::compareTo);
            ps.setString(i, StringUtils.join(p, ","));
        } else {
            ps.setString(i, null);
        }
    }

    @Override
    public List<E> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value;
        value = rs.getString(columnName);
        if (StringUtils.isBlank(StringUtils.trim(value))) {
            return Lists.newArrayList();
        }
        return Splitter.on(",").splitToList(value).stream().map(e -> codeOf(Integer.parseInt(e))).collect(Collectors.toList());
    }

    @Override
    public List<E> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value;
        value = rs.getString(columnIndex);
        if (StringUtils.isBlank(StringUtils.trim(value))) {
            return Lists.newArrayList();
        }
        return Splitter.on(",").splitToList(value).stream().map(e -> codeOf(Integer.parseInt(e))).collect(Collectors.toList());
    }

    @Override
    public List<E> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value;
        value = cs.getString(columnIndex);
        if (StringUtils.isBlank(StringUtils.trim(value))) {
            return Lists.newArrayList();
        }
        return Splitter.on(",").splitToList(value).stream().map(e -> codeOf(Integer.parseInt(e))).collect(Collectors.toList());
    }

    /**
     * 枚举类型转换
     *
     * @param code 数据库中存储的自定义code属性
     * @return code对应的枚举类
     */
    private E codeOf(int code) {
        try {
            return EnumUtil.codeOf(type, code);
        } catch (Exception e) {
            throw new IllegalArgumentException("Cannot convert " + code + " to " + type.getSimpleName() + " by code " +
                    "value.", e);
        }
    }
}
